package cn.xo68.boot.auth.core.shiro;

import cn.xo68.boot.auth.core.web.Oauth2TokenDiscern;
import cn.xo68.boot.auth.core.properties.OAuthResourceProperties;
import cn.xo68.core.util.StringTools;
import cn.xo68.core.util.UUIDUtils;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionException;
import org.apache.shiro.session.mgt.*;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.WebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;

/**
 * http会话管理器：无状态，请求开始时开始，结束时丢失
 * @author wuxie
 * @date 2018-8-8
 */
public class HttpWebSessionManager implements WebSessionManager {

    public final static Logger logger = LoggerFactory.getLogger(HttpWebSessionManager.class);



    private final OAuthResourceProperties oAuthResourceProperties;
    /**
     * 用于读取session中的令牌
     */
    private final SimpleCookie simpleCookie;

    public HttpWebSessionManager(OAuthResourceProperties oAuthResourceProperties, SimpleCookie simpleCookie) {
        this.oAuthResourceProperties = oAuthResourceProperties;
        this.simpleCookie = simpleCookie;
    }

    @Override
    public boolean isServletContainerSessions() {
        return true;
    }

    @Override
    public Session start(SessionContext sessionContext) {
        if (!WebUtils.isHttp(sessionContext)) {
            String msg = "SessionContext must be an HTTP compatible implementation.";
            throw new IllegalArgumentException(msg);
        }
        Session session=createSession(sessionContext);
        return session;
    }



    @Override
    public Session getSession(SessionKey sessionKey) throws SessionException {
        if (!WebUtils.isHttp(sessionKey)) {
            String msg = "SessionKey must be an HTTP compatible implementation.";
            throw new IllegalArgumentException(msg);
        }

        HttpServletRequest request = WebUtils.getHttpRequest(sessionKey);
        //HttpServletResponse response = WebUtils.getHttpResponse((sessionKey);

        Session session = getSession(request);

        if (session == null) {
            session = newSessionInstance(request);
            storeSession(request,session);
        }

        return session;
    }

    protected Serializable getSessionId(ServletRequest servletRequest) {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String sessionId=StringTools.EMPTY;
        try{
            Oauth2TokenDiscern oauth2TokenDiscern=new Oauth2TokenDiscern(request, true, true, true, this.simpleCookie);
            sessionId=oauth2TokenDiscern.getAccessToken();
        }catch (OAuthProblemException e){

        }catch (OAuthSystemException e){

        }
        if(StringTools.isEmpty(sessionId)){
            sessionId = generateSessionId();
        }
        return sessionId;
    }

    protected Session newSessionInstance(HttpServletRequest request) {
        SimpleSession session= new SimpleSession();
        Serializable sessionId = getSessionId(request);
        session.setId(sessionId);

        return session;
    }

    protected Session createSession(SessionContext sessionContext){
        HttpServletRequest request = WebUtils.getHttpRequest(sessionContext);
        //HttpServletResponse response = WebUtils.getHttpResponse(sessionContext);
        Session session=this.newSessionInstance(request);
        storeSession(request,session);
        return session;
    }

    /**
     * 保存会话到 request.attribute
     * @param request
     * @param session
     */
    private void storeSession(HttpServletRequest request,Session session){
        request.setAttribute(this.oAuthResourceProperties.getSessionIdAttr(),session.getId());
        request.setAttribute(this.oAuthResourceProperties.getSessionValueAttr(),session);
    }

    private Session getSession(HttpServletRequest request){
        return (Session) request.getAttribute(this.oAuthResourceProperties.getSessionValueAttr());
    }


    private String generateSessionId(){
        return UUIDUtils.createUUId();
    }
}
